import type { configState, delInfoState, ApiProps, tableInfoState } from '@/types/hooks'
import type { FunctionalComponent } from 'vue'
import type { PaginationProps } from 'naive-ui'
import { NPagination } from 'naive-ui'
import { isString, omit } from 'lodash-es'
import http from '@/service/http'

export function useApi<T>(config: configState) {
  /**
   * 初始化默认值
   * */
  const tableInfo = reactive<tableInfoState<T>>({
    showSearch: true,
    listLoading: false,
    total: 0,
    tableData: [],
    queryForm: {
      current: 1,
      size: 20,
    },
    pageSizes: [10, 20, 30, 40, 50, 80, 100, 200, 400, 500],
    checkedRowKeys: [],
  })

  if (config.initForm) {
    tableInfo.queryForm = {
      ...tableInfo.queryForm,
      ...config.initForm,
    }
  }
  if (config.isPaging === undefined) {
    config.isPaging = true
  }
  /**
   * 重置查询条件
   * */
  const handReset = () => {
    Object.keys(omit(tableInfo.queryForm, ['current', 'size'])).forEach((key) => {
      tableInfo.queryForm[key] = null
    })
    nextTick(() => {
      tableInfo.queryForm = {
        current: 1,
        size: tableInfo.queryForm.size,
        ...config.initForm,
      }
      queryData()
    })
  }

  /**
   * 列表请求
   * */
  const getRequest = async (params) => {
    if (config?.getParams) {
      params = config?.getParams(params)
    }
    let res
    if (config?.getApi) {
      const apiConfig: ApiProps = isString(config.getApi)
        ? {
            api: config.getApi as string,
            method: 'get',
          }
        : (config.getApi as ApiProps)
      res = await http[apiConfig.method](apiConfig.api, params)
    } else {
      res = await config.getData(params)
      if (res.data?.rows) {
        res.data.records = res.data.rows
        delete res.data.rows
      }
    }
    const { data } = res
    if (data && data?.rows) {
      // 兼容后端返回的分页数据格式
      data.records = data.rows
      delete data.rows
    }
    if (!config?.dataMap) return data
    if (!config.isPaging) return config.dataMap(data)
    data.records = config.dataMap(data.records)
    return data
  }

  const fetchData = async () => {
    tableInfo.listLoading = true
    const data = await getRequest(tableInfo.queryForm)
    tableInfo.tableData = config.isPaging ? data.records : data
    if (config.isPaging) {
      tableInfo.total = Math.ceil(Number(data.total) / tableInfo.queryForm.size)
      if (tableInfo.tableData.length === 0 && tableInfo.queryForm.current > 1) {
        // 如果当前页没有数据，且当前页大于1，则返回上一页
        tableInfo.queryForm.current -= 1
        fetchData()
      }
    }
    tableInfo.listLoading = false
    if (config?.fetchOver) {
      config?.fetchOver()
    }
  }

  const queryData = () => {
    tableInfo.tableData = []
    tableInfo.queryForm.current = 1
    fetchData()
  }

  /**
   *  添加编辑(已废弃,但为了兼容旧代码保留)
   * */
  const handAdd = (row?) => {
    if (config?.addRef) {
      if (row) {
        config.addRef.value.open(toRaw(row))
      } else {
        config.addRef.value.open(null)
      }
    }
  }
  /**
   *  删除相关
   * */
  const delInfo: delInfoState = reactive({
    delLoading: false,
    row: {
      id: '',
    },
  })
  const handDel = (row?) => {
    if (row) {
      delInfo.row = row
    } else {
      if (tableInfo.checkedRowKeys.length === 0) {
        msgUtil.$message.warning('请选择要删除的数据')
        return
      }
      delete delInfo.row
    }
    msgUtil.$dialog.warning({
      title: '温馨提示',
      content: '确认要删除选中数据吗？',
      positiveText: '确定',
      negativeText: '取消',
      onPositiveClick: () => {
        delConfirm()
      },
    })
  }
  const delRequest = async (params) => {
    let res
    if (config?.delApi) {
      const apiConfig: ApiProps = isString(config.delApi)
        ? {
            api: config.delApi as string,
            method: 'post',
          }
        : (config.delApi as ApiProps)
      if (apiConfig?.path) {
        res = await http[apiConfig.method || 'post'](`${apiConfig.api}/${params.ids.toString()}`)
      } else {
        if (apiConfig.one) {
          params = {
            id: params.ids[0],
          }
        } else if (apiConfig.isArray) {
          params = params.ids
        }
        res = await http[apiConfig.method || 'post'](apiConfig.api, params)
      }
    } else {
      res = await config.delData(params)
    }
    const { code, msg } = res
    if (code !== 0) {
      // 抛出异常msg
      throw new Error(msg)
    }
  }
  const delConfirm = async () => {
    if (!config?.delData && !config?.delApi) {
      return msgUtil.$message.error('未配置删除方法')
    }
    const ids = delInfo?.row ? [delInfo.row[config?.delKey || 'id']] : tableInfo.checkedRowKeys
    delInfo.delLoading = true
    try {
      await delRequest({ ids })
      msgUtil.$message.success('删除成功')
      if (config?.delSuccess) {
        config?.delSuccess()
      }
      fetchData()
    } finally {
      delInfo.delLoading = false
    }
  }
  /**
   * 分页组件
   * */
  const pageChange = (page: number) => {
    tableInfo.queryForm.current = page
    fetchData()
  }
  const sizeChange = (size: number) => {
    tableInfo.queryForm.size = size
    tableInfo.queryForm.current = 1
    fetchData()
  }

  const YPagination: FunctionalComponent<PaginationProps> = (props: PaginationProps, { slots }) =>
    h(
      NPagination,
      {
        page: tableInfo.queryForm.current,
        pageSize: tableInfo.queryForm.size,
        pageSizes: tableInfo.pageSizes,
        pageCount: tableInfo.total,
        showQuickJumper: true,
        showSizePicker: true,
        onUpdatePage: pageChange,
        onUpdatePageSize: sizeChange,
        ...props,
      },
      slots,
    )

  /**
   * 默认初始化请求列表
   * */
  onMounted(() => {
    if (config.isRequest || config.isRequest === undefined) {
      queryData()
    }
  })

  const { height: containerHeight } = useElementSize(config.container)
  const tableMaxHeight = computed(() => containerHeight.value - 70)
  return {
    YPagination: config.isPaging ? YPagination : undefined,
    tableMaxHeight,
    tableInfo,
    delInfo,
    handReset,
    pageChange,
    sizeChange,
    fetchData,
    queryData,
    handAdd,
    delConfirm,
    handDel,
  }
}
